#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sqlite3.h>

/* 该程序实现UDP网络通信 */
/* 步骤：
* 1、socket建立套接字，其返回值-1则表示创建失败
* 2、Bind配置本地端口和IP，用于绑定对象，此程序绑定服务器
* 3、启动监听listen，监听和接收服务器的请求
* 4、在监听到请求之后，需要接受/拒绝请求并建立连接，Accept
* 5、创建连接之后，就要进行信息的接受Recv，然后处理信息发送回信息Send()
* 6、一次通信完毕，关闭套接字接口Close
*/
char NUM_OPEN;//用于获取灯光打开状态
static int myfunc_open(void *p, int argc, char **argv, char **argvv)//回调函数，用于获取
{
	NUM_OPEN = *argv[0];
	return 0;
}
static int myfunc(void *p, int argc, char **argv, char **argvv)
{
	int i;
	*(int *)p = 0;
	NUM_OPEN = *argv[0];
	for (i = 0; i < argc; ++i)
		printf("%s = %s ", argvv[i], argv[i] ? argv[i] : "NULL");
	printf("\n");
	return 0;
}

void part(char* data, char tmp[], char humi[])
{
	char str[] = ",='\n'";
	strtok(data, str);			// card_id i
	strtok(NULL, str);			// card_id i
	strcpy(tmp, strtok(NULL, str));	//id
	strtok(NULL, str);			// card_id i
	strcpy(humi, strtok(NULL, str));	//id
	strtok(NULL, str);			// card_id i
}

int main()
{
	sqlite3 *db;
	char *err = 0;
	int ret_sqlite = 0;// 记录表的长度，单次执行时有效
	int empty = 1;

	sqlite3 *db_open;
	char *err_open = 0;
	int ret_sqlite_open = 0;
	int empty_open = 1;

	char insert_buff[100] = { 0 };

	// 1、socket建立套接字，其返回值-1则表示创建失败
	int fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (fd < 0)
	{
		perror("fd of socket faild ::");
	}
	printf("socket OK\n");

	//2、配置本地端口和IP，用于绑定对象，此程序绑定服务器
	struct sockaddr_in dst;
	dst.sin_family = AF_INET;
	dst.sin_port = htons(8202);
	dst.sin_addr.s_addr = INADDR_ANY;
	int ret = bind(fd, (struct sockaddr *)&dst, 16);
	if (ret < 0)
	{
		perror("bind faild ::");
	}
	printf("bind OK\n");

	// 与存放温湿度的数据库建立链接，查看数据库内容
	ret_sqlite = sqlite3_open("/var/www/xuedao", &db);
	if (ret_sqlite != SQLITE_OK)
	{
		printf("sqlite3 open error\n");
		exit(1);
	}

	ret_sqlite = sqlite3_exec(db,"delete from hb" , myfunc, &empty, &err);
	ret_sqlite = sqlite3_exec(db, "select * from hb where id=(select MAX(id) from hb)", myfunc, &empty, &err);
	if (ret_sqlite != SQLITE_OK)
	{
		printf("11");
		printf("sqlite3 exec error 1\n");
		sqlite3_close(db);
		exit(1);
	}
	// 与灯光开关数据库建立连接，控制灯光数据
	ret_sqlite_open = sqlite3_open("/var/www/xuedao", &db_open);
	if (ret_sqlite_open != SQLITE_OK)
	{
		printf("sqlite3 open error\n");
		exit(1);
	}


	// 3、启动监听listen，监听和接收服务器的请求
	// 4、在监听到请求之后，需要接受/拒绝请求并建立连接，Accept
	// 5、创建连接之后，就要进行信息的接受Recv，然后处理信息发送回信息Send()
	struct sockaddr_in send;
	int send_len = 0;
	int _send_len = sizeof(dst);
	int sqlite_id = 0;
	int e = 4e8;
	while (1)
	{
		char data[1024] = { 0 };
		char id[17] = { 0 };
		char humi[3] = { 0 };
		char tmp[3] = { 0 };
		int ret = recvfrom(fd, data, 1024, 0, (struct sockaddr *)&send, &send_len);
		printf("data = %s\n", data);
		if (ret < 0)
		{
			perror("recvfrom faild ::");
		}

		part(data, tmp, humi);
		ret_sqlite_open = sqlite3_exec(db, "select * from hb_open", myfunc_open, &empty_open, &err_open);
		if (ret_sqlite_open != SQLITE_OK)
		{
			printf("33");
			printf("sqlite3 exec error 2\n");
			sqlite3_close(db_open);
			exit(1);
		}
		ret = sendto(fd, &NUM_OPEN, 1, 0, (struct sockaddr *) &send, _send_len);
		if (ret < 0)
		{
			perror("sendto faild ::");
		}

		// 将数据写入数据库中
		sprintf(insert_buff, "insert into hb values(%d,%s,%s)", sqlite_id, tmp, humi);
		++sqlite_id;
		printf("%s\n", insert_buff);
		ret_sqlite = sqlite3_exec(db, insert_buff, NULL, &empty, &err);
		if (ret_sqlite != SQLITE_OK)
		{
			printf("22");
			perror("sqlite3 exec error 3\n");
			sqlite3_close(db);
			exit(1);
		}
	}
	close(fd);
	sqlite3_close(db);

	return 0;
}

